! Earth System Modeling Framework
! Copyright 2002-2003, University Corporation for Atmospheric Research,
! Massachusetts Institute of Technology, Geophysical Fluid Dynamics
! Laboratory, University of Michigan, National Centers for Environmental
! Prediction, Los Alamos National Laboratory, Argonne National Laboratory,
! NASA Goddard Space Flight Center.
! Licensed under the GPL.
!
!==============================================================================
!
!     ESMF Time Module
module ESMF_TimeMod
  !
  !==============================================================================
  !
  ! This file contains the Time class definition and all Time class methods.
  !
  !------------------------------------------------------------------------------
  ! INCLUDES
#include <ESMF_TimeMgr.inc>

  !==============================================================================
  !BOPI
  ! !MODULE: ESMF_TimeMod
  !
  ! !DESCRIPTION:
  ! Part of Time Manager F90 API wrapper of C++ implemenation
  !
  ! Defines F90 wrapper entry points for corresponding
  ! C++ class {\tt ESMC\_Time} implementation
  !
  ! See {\tt ../include/ESMC\_Time.h} for complete description
  !
  !------------------------------------------------------------------------------
  ! !USES:
  ! inherit from ESMF base class
  use ESMF_BaseMod

  ! inherit from base time class
  use ESMF_BaseTimeMod

  ! associated derived types
  use ESMF_TimeIntervalMod
  use ESMF_CalendarMod
  use ESMF_ShrTimeMod, only : ESMF_Time
  ! added by Jhe
  use ESMF_Stubs

  implicit none
  !
  !------------------------------------------------------------------------------
  ! !PRIVATE TYPES:
  private
  !------------------------------------------------------------------------------
  !     ! ESMF_Time
  !
  !     ! F90 class type to match C++ Time class in size only;
  !     !  all dereferencing within class is performed by C++ implementation

  ! move to ESMF_ShrTimeMod
  !     type ESMF_Time
  !       type(ESMF_BaseTime) :: basetime           ! inherit base class
  !       ! time instant is expressed as year + basetime
  !       integer :: YR
  !       type(ESMF_Calendar), pointer :: calendar  ! associated calendar
  !     end type
  !------------------------------------------------------------------------------
  ! !PUBLIC DATA:

  !------------------------------------------------------------------------------
  ! !PUBLIC TYPES:
  public ESMF_Time
  !------------------------------------------------------------------------------
  !
  ! !PUBLIC MEMBER FUNCTIONS:
  public ESMF_TimeGet
  public ESMF_TimeSet
  public ESMF_TimePrint

  ! Required inherited and overridden ESMF_Base class methods

  public ESMF_TimeCopy
  public ESMF_SetYearWidth

  ! !PRIVATE MEMBER FUNCTIONS:

  private ESMF_TimeGetDayOfYear
  private ESMF_TimeGetDayOfYearInteger

  ! Inherited and overloaded from ESMF_BaseTime

  public operator(+)
  public ESMF_TimeInc

  public operator(-)
  private ESMF_TimeDec
  private ESMF_TimeDiff

  public operator(.EQ.)
  public ESMF_TimeEQ

  public operator(.NE.)
  public ESMF_TimeNE

  public operator(.LT.)
  public ESMF_TimeLT

  public operator(.GT.)
  public ESMF_TimeGT

  public operator(.LE.)
  public ESMF_TimeLE

  public operator(.GE.)
  public ESMF_TimeGE

  !EOPI

  !------------------------------------------------------------------------------
  ! The following line turns the CVS identifier string into a printable variable.
  character(*), parameter, private :: version = &
       '$Id$'

  integer :: yearWidth = 4

  !==============================================================================
  !
  ! INTERFACE BLOCKS
  !
  !==============================================================================
  !BOP
  ! !INTERFACE:
  interface ESMF_TimeGetDayOfYear

     ! !PRIVATE MEMBER FUNCTIONS:
     module procedure ESMF_TimeGetDayOfYearInteger

     ! !DESCRIPTION:
     !     This interface overloads the {\tt ESMF\_GetDayOfYear} method
     !     for the {\tt ESMF\_Time} class
     !
     !EOP
  end interface ESMF_TimeGetDayOfYear
  !
  !------------------------------------------------------------------------------
  !BOP
  ! !INTERFACE:
  interface operator(+)

     ! !PRIVATE MEMBER FUNCTIONS:
     module procedure ESMF_TimeInc, ESMF_TimeInc2

     ! !DESCRIPTION:
     !     This interface overloads the + operator for the {\tt ESMF\_Time} class
     !
     !EOP
  end interface operator(+)
  !
  !------------------------------------------------------------------------------
  !BOP
  ! !INTERFACE:
  interface assignment (=)

     ! !PRIVATE MEMBER FUNCTIONS:
     module procedure ESMF_TimeCopy

     ! !DESCRIPTION:
     !     This interface overloads the = operator for the {\tt ESMF\_Time} class
     !
     !EOP
  end interface assignment (=)
  !
  !------------------------------------------------------------------------------
  !BOP
  ! !INTERFACE:
  interface operator(-)

     ! !PRIVATE MEMBER FUNCTIONS:
     module procedure ESMF_TimeDec, ESMF_TimeDec2

     ! !DESCRIPTION:
     !     This interface overloads the - operator for the {\tt ESMF\_Time} class
     !
     !EOP
  end interface operator(-)
  !
  !------------------------------------------------------------------------------
  !BOP
  ! !INTERFACE:
  interface operator(-)

     ! !PRIVATE MEMBER FUNCTIONS:
     module procedure ESMF_TimeDiff

     ! !DESCRIPTION:
     !     This interface overloads the - operator for the {\tt ESMF\_Time} class
     !
     !EOP
  end interface operator(-)
  !
  !------------------------------------------------------------------------------
  !BOP
  ! !INTERFACE:
  interface operator(.EQ.)

     ! !PRIVATE MEMBER FUNCTIONS:
     module procedure ESMF_TimeEQ

     ! !DESCRIPTION:
     !     This interface overloads the .EQ. operator for the {\tt ESMF\_Time} class
     !
     !EOP
  end interface operator(.EQ.)
  !
  !------------------------------------------------------------------------------
  !BOP
  ! !INTERFACE:
  interface operator(.NE.)

     ! !PRIVATE MEMBER FUNCTIONS:
     module procedure ESMF_TimeNE

     ! !DESCRIPTION:
     !     This interface overloads the .NE. operator for the {\tt ESMF\_Time} class
     !
     !EOP
  end interface operator(.NE.)
  !
  !------------------------------------------------------------------------------
  !BOP
  ! !INTERFACE:
  interface operator(.LT.)

     ! !PRIVATE MEMBER FUNCTIONS:
     module procedure ESMF_TimeLT

     ! !DESCRIPTION:
     !     This interface overloads the .LT. operator for the {\tt ESMF\_Time} class
     !
     !EOP
  end interface operator(.LT.)
  !
  !------------------------------------------------------------------------------
  !BOP
  ! !INTERFACE:
  interface operator(.GT.)

     ! !PRIVATE MEMBER FUNCTIONS:
     module procedure ESMF_TimeGT

     ! !DESCRIPTION:
     !     This interface overloads the .GT. operator for the {\tt ESMF\_Time} class
     !
     !EOP
  end interface operator(.GT.)
  !
  !------------------------------------------------------------------------------
  !BOP
  ! !INTERFACE:
  interface operator(.LE.)

     ! !PRIVATE MEMBER FUNCTIONS:
     module procedure ESMF_TimeLE

     ! !DESCRIPTION:
     !     This interface overloads the .LE. operator for the {\tt ESMF\_Time} class
     !
     !EOP
  end interface operator(.LE.)
  !
  !------------------------------------------------------------------------------
  !BOP
  ! !INTERFACE:
  interface operator(.GE.)

     ! !PRIVATE MEMBER FUNCTIONS:
     module procedure ESMF_TimeGE

     ! !DESCRIPTION:
     !     This interface overloads the .GE. operator for the {\tt ESMF\_Time} class
     !
     !EOP
  end interface operator(.GE.)
  !
  !------------------------------------------------------------------------------

  !==============================================================================

contains

  !==============================================================================
  !------------------------------------------------------------------------------
  !BOP
  ! !IROUTINE: ESMF_TimeGet - Get value in user-specified units

  ! !INTERFACE:
  !      subroutine ESMF_TimeGet(time, YY, YRl, MM, DD, D, Dl, H, M, S, Sl, MS, &
  !                              US, NS, d_, h_, m_, s_, ms_, us_, ns_, Sn, Sd, &
  !                              dayOfYear, dayOfYear_r8, dayOfYear_intvl,      &
  !                              timeString, rc)

  recursive subroutine ESMF_TimeGet(time, YY, MM, DD, D, Dl, H, M, S, MS, &
       Sn, Sd, &
       dayOfYear, dayOfYear_r8, dayOfYear_intvl,      &
       timeString, rc)

    ! !ARGUMENTS:
    type(ESMF_Time), intent(in) :: time
    integer, intent(out), optional :: YY
    !      integer(ESMF_KIND_I8), intent(out), optional :: YRl
    integer, intent(out), optional :: MM
    integer, intent(out), optional :: DD
    integer, intent(out), optional :: D
    integer(ESMF_KIND_I8), intent(out), optional :: Dl
    integer, intent(out), optional :: H
    integer, intent(out), optional :: M
    integer, intent(out), optional :: S
    !      integer(ESMF_KIND_I8), intent(out), optional :: Sl
    integer, intent(out), optional :: MS
    !      integer, intent(out), optional :: US
    !      integer, intent(out), optional :: NS
    !      double precision, intent(out), optional :: d_
    !      double precision, intent(out), optional :: h_
    !      double precision, intent(out), optional :: m_
    !      double precision, intent(out), optional :: s_
    !      double precision, intent(out), optional :: ms_
    !      double precision, intent(out), optional :: us_
    !      double precision, intent(out), optional :: ns_
    integer, intent(out), optional :: Sn
    integer, intent(out), optional :: Sd
    integer, intent(out), optional :: dayOfYear
    real(ESMF_KIND_R8), intent(out), optional :: dayOfYear_r8
    character (len=*), intent(out), optional :: timeString
    type(ESMF_TimeInterval), intent(out), optional :: dayOfYear_intvl
    integer, intent(out), optional :: rc


    ! !DESCRIPTION:
    !     Get the value of the {\tt ESMF\_Time} in units specified by the user
    !     via F90 optional arguments.
    !
    !     Time manager represents and manipulates time internally with integers
    !     to maintain precision. Hence, user-specified floating point values are
    !     converted internally from integers.
    !
    !     See {\tt ../include/ESMC\_BaseTime.h and ../include/ESMC\_Time.h} for
    !     complete description.
    !
    !     The arguments are:
    !     \begin{description}
    !     \item[time]
    !          The object instance to query
    !     \item[{[YY]}]
    !          Integer year CCYR (>= 32-bit)
    !     \item[{[YRl]}]
    !          Integer year CCYR (large, >= 64-bit)
    !     \item[{[MM]}]
    !          Integer month 1-12
    !     \item[{[DD]}]
    !          Integer day of the month 1-31
    !     \item[{[D]}]
    !          Integer Julian days (>= 32-bit)
    !     \item[{[Dl]}]
    !          Integer Julian days (large, >= 64-bit)
    !     \item[{[H]}]
    !          Integer hours
    !     \item[{[M]}]
    !          Integer minutes
    !     \item[{[S]}]
    !          Integer seconds (>= 32-bit)
    !     \item[{[Sl]}]
    !          Integer seconds (large, >= 64-bit)
    !     \item[{[MS]}]
    !          Integer milliseconds
    !     \item[{[US]}]
    !          Integer microseconds
    !     \item[{[NS]}]
    !          Integer nanoseconds
    !     \item[{[d\_]}]
    !          Double precision days
    !     \item[{[h\_]}]
    !          Double precision hours
    !     \item[{[m\_]}]
    !          Double precision minutes
    !     \item[{[s\_]}]
    !          Double precision seconds
    !     \item[{[ms\_]}]
    !          Double precision milliseconds
    !     \item[{[us\_]}]
    !          Double precision microseconds
    !     \item[{[ns\_]}]
    !          Double precision nanoseconds
    !     \item[{[Sn]}]
    !          Integer fractional seconds - numerator
    !     \item[{[Sd]}]
    !          Integer fractional seconds - denominator
    !     \item[{[rc]}]
    !          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
    !     \end{description}
    !
    ! !REQUIREMENTS:
    !     TMG2.1, TMG2.5.1, TMG2.5.6
    !EOP
    type(ESMF_TimeInterval) :: day_step
    integer :: ierr
    TYPE(ESMF_Time) :: begofyear
    TYPE(ESMF_TimeInterval) :: difftobegofyear
    INTEGER :: year, month, dayofmonth, hour, minute, second
    INTEGER :: i
    INTEGER(ESMF_KIND_I8) :: cnt

    ierr = ESMF_SUCCESS

    IF ( PRESENT( YY ) ) THEN
       YY = time%YR
    ENDIF
    IF ( PRESENT( MM ) ) THEN
       CALL timegetmonth( time, MM )
    ENDIF
    IF ( PRESENT( DD ) ) THEN
       CALL timegetdayofmonth( time, DD )
    ENDIF

    if (present(d) .or. present(dl)) then
       cnt = 0
       do i = 0,time%yr-1
          cnt = cnt + ndaysinyear(i,time%calendar%type)
       enddo
       do i = time%yr,-1
          cnt = cnt - ndaysinyear(i,time%calendar%type)
       enddo
       call timegetmonth(time,month)
       do i = 1,month-1
          cnt = cnt + ndaysinmonth(time%yr,i,time%calendar%type)
       enddo
       call timegetdayofmonth( time, dayofmonth)
       cnt = cnt + dayofmonth
       if (present(d)) then
          d = cnt
       endif
       if (present(dl)) then
          dl = cnt
       endif
    endif
    !
    !$$$ push HMS down into ESMF_BaseTime
    IF ( PRESENT( H ) ) THEN
       H = mod( time%basetime%S, SECONDS_PER_DAY ) / SECONDS_PER_HOUR
    ENDIF
    IF ( PRESENT( M ) ) THEN
       M = mod( time%basetime%S, SECONDS_PER_HOUR) / SECONDS_PER_MINUTE
    ENDIF
    IF ( PRESENT( S ) ) THEN
       S = mod( time%basetime%S, SECONDS_PER_MINUTE )
    ENDIF

    IF ( PRESENT( S ) .AND. PRESENT( DD ) ) THEN
       IF ( ( .NOT. PRESENT( H ) ) .AND. ( .NOT. PRESENT( M ) ) ) THEN
          S = mod( time%basetime%S, SECONDS_PER_DAY )
       ENDIF
    ENDIF
    IF ( PRESENT( MS ) ) THEN
       IF ( time%basetime%Sd /= 0 ) THEN
          MS = NINT( ( time%basetime%Sn*1.0D0 / time%basetime%Sd*1.0D0 ) * 1000.0D0 )
       ELSE
          MS = 0
       ENDIF
    ENDIF
    IF ( PRESENT( Sd ) .AND. PRESENT( Sn ) ) THEN
       Sd = time%basetime%Sd
       Sn = time%basetime%Sn
    ENDIF
    IF ( PRESENT( dayOfYear ) ) THEN
       CALL ESMF_TimeGetDayOfYear( time, dayOfYear, rc=ierr )
    ENDIF
    IF ( PRESENT( timeString ) ) THEN
       ! This duplication for YMD is an optimization that avoids calling
       ! timegetmonth() and timegetdayofmonth() when it is not needed.
       year = time%YR
       CALL timegetmonth( time, month )
       CALL timegetdayofmonth( time, dayofmonth )
       !$$$ push HMS down into ESMF_BaseTime
       hour = mod( time%basetime%S, SECONDS_PER_DAY ) / SECONDS_PER_HOUR
       minute = mod( time%basetime%S, SECONDS_PER_HOUR) / SECONDS_PER_MINUTE
       second = mod( time%basetime%S, SECONDS_PER_MINUTE )
       CALL ESMFold_TimeGetString( year, month, dayofmonth, &
            hour, minute, second, timeString )
    ENDIF
    IF ( PRESENT( dayOfYear_intvl ) ) THEN
       year = time%YR
       CALL ESMF_TimeSet( begofyear, yy=year, mm=1, dd=1, s=0, &
            calendar=time%calendar, rc=ierr )
       IF ( ierr == ESMF_FAILURE)THEN
          rc = ierr
          RETURN
       END IF
       dayOfYear_intvl = time - begofyear
    ENDIF
    IF ( PRESENT( dayOfYear_r8) ) THEN
       year = time%YR
       CALL ESMF_TimeSet( begofyear, yy=year, mm=1, dd=1, s=0, &
            calendar=time%calendar, rc=ierr )
       IF ( ierr == ESMF_FAILURE)THEN
          rc = ierr
          RETURN
       END IF
       CALL ESMF_TimeIntervalSet( day_step, d=1, s=0, rc=ierr )
       IF ( ierr == ESMF_FAILURE)THEN
          rc = ierr
          RETURN
       END IF
       difftobegofyear = time - begofyear + day_step
       CALL ESMF_TimeIntervalGet( difftobegofyear, d_r8=dayOfYear_r8, rc=ierr )
       IF ( ierr == ESMF_FAILURE)THEN
          rc = ierr
          RETURN
       END IF
    ENDIF

    IF ( PRESENT( rc ) ) THEN
       rc = ierr
    ENDIF

  end subroutine ESMF_TimeGet

  !------------------------------------------------------------------------------
  !BOP
  ! !IROUTINE: ESMF_TimeSet - Initialize via user-specified unit set

  ! !INTERFACE:
  !      subroutine ESMF_TimeSet(time, YY, YRl, MM, DD, D, Dl, H, M, S, Sl, &
  !                              MS, US, NS, d_, h_, m_, s_, ms_, us_, ns_, &
  !                              Sn, Sd, calendar, calkindflag, rc)

  subroutine ESMF_TimeSet(time, YY, MM, DD, D, Dl, H, M, S, &
       MS, &
       Sn, Sd, calendar, calkindflag, rc)

    ! !ARGUMENTS:
    type(ESMF_Time), intent(inout) :: time
    integer, intent(in), optional :: YY
    !      integer(ESMF_KIND_I8), intent(in), optional :: YRl
    integer, intent(in), optional :: MM
    integer, intent(in), optional :: DD
    integer, intent(in), optional :: D
    integer(ESMF_KIND_I8), intent(in), optional :: Dl
    integer, intent(in), optional :: H
    integer, intent(in), optional :: M
    integer, intent(in), optional :: S
    !      integer(ESMF_KIND_I8), intent(in), optional :: Sl
    integer, intent(in), optional :: MS
    !      integer, intent(in), optional :: US
    !      integer, intent(in), optional :: NS
    !      double precision, intent(in), optional :: d_
    !      double precision, intent(in), optional :: h_
    !      double precision, intent(in), optional :: m_
    !      double precision, intent(in), optional :: s_
    !      double precision, intent(in), optional :: ms_
    !      double precision, intent(in), optional :: us_
    !      double precision, intent(in), optional :: ns_
    integer, intent(in), optional :: Sn
    integer, intent(in), optional :: Sd
    type(ESMF_Calendar), intent(in), target, optional :: calendar
    type(ESMF_CalKind_Flag), intent(in),  optional :: calkindflag
    integer, intent(out), optional :: rc

    ! locals
    INTEGER :: ierr
    logical :: dset

    ! !DESCRIPTION:
    !     Initializes a {\tt ESMF\_Time} with a set of user-specified units
    !     via F90 optional arguments.
    !
    !     Time manager represents and manipulates time internally with integers
    !     to maintain precision. Hence, user-specified floating point values are
    !     converted internally to integers.
    !
    !     See {\tt ../include/ESMC\_BaseTime.h and ../include/ESMC\_Time.h} for
    !     complete description.
    !
    !     The arguments are:
    !     \begin{description}
    !     \item[time]
    !          The object instance to initialize
    !     \item[{[YY]}]
    !          Integer year CCYR (>= 32-bit)
    !     \item[{[YRl]}]
    !          Integer year CCYR (large, >= 64-bit)
    !     \item[{[MM]}]
    !          Integer month 1-12
    !     \item[{[DD]}]
    !          Integer day of the month 1-31
    !     \item[{[D]}]
    !          Integer Julian days (>= 32-bit)
    !     \item[{[Dl]}]
    !          Integer Julian days (large, >= 64-bit)
    !     \item[{[H]}]
    !          Integer hours
    !     \item[{[M]}]
    !          Integer minutes
    !     \item[{[S]}]
    !          Integer seconds (>= 32-bit)
    !     \item[{[Sl]}]
    !          Integer seconds (large, >= 64-bit)
    !     \item[{[MS]}]
    !          Integer milliseconds
    !     \item[{[US]}]
    !          Integer microseconds
    !     \item[{[NS]}]
    !          Integer nanoseconds
    !     \item[{[d\_]}]
    !          Double precision days
    !     \item[{[h\_]}]
    !          Double precision hours
    !     \item[{[m\_]}]
    !          Double precision minutes
    !     \item[{[s\_]}]
    !          Double precision seconds
    !     \item[{[ms\_]}]
    !          Double precision milliseconds
    !     \item[{[us\_]}]
    !          Double precision microseconds
    !     \item[{[ns\_]}]
    !          Double precision nanoseconds
    !     \item[{[Sn]}]
    !          Integer fractional seconds - numerator
    !     \item[{[Sd]}]
    !          Integer fractional seconds - denominator
    !     \item[{[cal]}]
    !          Associated {\tt Calendar}
    !     \item[{[tz]}]
    !          Associated timezone (hours offset from GMT, e.g. EST = -5)
    !     \item[{[rc]}]
    !          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
    !     \end{description}
    !
    ! !REQUIREMENTS:
    !     TMGn.n.n
    !EOP
    !  PRINT *,'DEBUG:  BEGIN ESMF_TimeSet()'
    !$$$ push this down into ESMF_BaseTime constructor

    IF ( PRESENT( rc ) ) then
       rc = ESMF_FAILURE
    ENDIF

    time%YR = 0
    time%basetime%S  = 0
    time%basetime%Sn = 0
    time%basetime%Sd = 0

    IF ( PRESENT(calendar) )THEN
       !  PRINT *,'DEBUG:  ESMF_TimeSet():  using passed-in calendar'
       IF ( .not. ESMF_CalendarInitialized( calendar ) )THEN
          call wrf_error_fatal( "Error:: ESMF_CalendarCreate not "// &
               "called on input Calendar")
       END IF
       !        call flush(6)
       !        write(6,*) 'tcx1 ESMF_TimeSet point to calendar'
       !        call flush(6)
       time%Calendar => calendar
    ELSE
       !  PRINT *,'DEBUG:  ESMF_TimeSet():  using default calendar'
       ! for the sake of WRF, check ESMF_IsInitialized, revised by Juanxiong He
       IF ( .not. ESMF_IsInitialized() )THEN
          call wrf_error_fatal( "Error:: ESMF_Initialize not called")
       END IF
       !        IF ( .not. ESMF_CalendarInitialized( defaultCal ) )THEN
       !           call wrf_error_fatal( "Error:: ESMF_Initialize not called")
       !        END IF
       if (present(calkindflag)) then
          !           write(6,*) 'tcx2 ESMF_TimeSet point to calendarkindflag',calkindflag%caltype
          !           call flush(6)
          if (calkindflag%caltype == ESMF_CALKIND_GREGORIAN%caltype) then
             time%Calendar => gregorianCal
          elseif (calkindflag%caltype == ESMF_CALKIND_NOLEAP%caltype) then
             time%Calendar => noleapCal
          else
             call wrf_error_fatal( "Error:: ESMF_TimeSet invalid calkindflag")
          endif
       else
          !           write(6,*) 'tcx3 ESMF_TimeSet point to defaultcal'
          !           call flush(6)
          time%Calendar => defaultCal
       endif
    END IF
    !      write(6,*) 'tcxn ESMF_TimeSet ',ESMF_CALKIND_NOLEAP%caltype
    !      call flush(6)
    !      write(6,*) 'tcxg ESMF_TimeSet ',ESMF_CALKIND_GREGORIAN%caltype
    !      call flush(6)
    !      write(6,*) 'tcxt ESMF_TimeSet ',time%calendar%type%caltype
    !      call flush(6)

    dset = .false.
    if (present(D)) then
       if (present(Dl)) CALL wrf_error_fatal( 'ESMF_TimeSet:  D and Dl not both valid')
       time%basetime%s = SECONDS_PER_DAY * INT(D-1,ESMF_KIND_I8)
       dset=.true.
    elseif (present(Dl)) then
       time%basetime%s = SECONDS_PER_DAY * Dl-1_ESMF_KIND_I8
       dset=.true.
    endif

    IF ( PRESENT( YY ) ) THEN
       !  PRINT *,'DEBUG:  ESMF_TimeSet():  YY = ',YY
       if (dset) CALL wrf_error_fatal( 'ESMF_TimeSet:  D or DL and YY,MM,DD not both valid')
       time%YR = YY
    ENDIF
    IF ( PRESENT( MM ) ) THEN
       if (dset) CALL wrf_error_fatal( 'ESMF_TimeSet:  D or DL and YY,MM,DD not both valid')
       !  PRINT *,'DEBUG:  ESMF_TimeSet():  MM = ',MM
       CALL timeaddmonths( time, MM, ierr )
       IF ( ierr == ESMF_FAILURE ) THEN
          IF ( PRESENT( rc ) ) THEN
             rc = ESMF_FAILURE
             RETURN
          ELSE
             CALL wrf_error_fatal( 'ESMF_TimeSet:  MM out of range' )
          ENDIF
       ENDIF
       !  PRINT *,'DEBUG:  ESMF_TimeSet():  back from timeaddmonths'
    ENDIF
    IF ( PRESENT( DD ) ) THEN
       if (dset) CALL wrf_error_fatal( 'ESMF_TimeSet:  D or DL and YY,MM,DD not both valid')
       !$$$ no check for DD in range of days of month MM yet
       !$$$ Must separate D and DD for correct interface!
       !  PRINT *,'DEBUG:  ESMF_TimeSet():  DD = ',DD
       time%basetime%S = time%basetime%S + &
            ( SECONDS_PER_DAY * INT( (DD-1), ESMF_KIND_I8 ) )
    ENDIF
    !$$$ push H,M,S,Sn,Sd,MS down into ESMF_BaseTime constructor
    IF ( PRESENT( H ) ) THEN
       !  PRINT *,'DEBUG:  ESMF_TimeSet():  H = ',H
       time%basetime%S = time%basetime%S + &
            ( SECONDS_PER_HOUR * INT( H, ESMF_KIND_I8 ) )
    ENDIF
    IF ( PRESENT( M ) ) THEN
       !  PRINT *,'DEBUG:  ESMF_TimeSet():  M = ',M
       time%basetime%S = time%basetime%S + &
            ( SECONDS_PER_MINUTE * INT( M, ESMF_KIND_I8 ) )
    ENDIF
    IF ( PRESENT( S ) ) THEN
       !  PRINT *,'DEBUG:  ESMF_TimeSet():  S = ',S
       time%basetime%S = time%basetime%S + &
            INT( S, ESMF_KIND_I8 )
    ENDIF
    IF ( PRESENT( Sn ) .AND. ( .NOT. PRESENT( Sd ) ) ) THEN
       CALL wrf_error_fatal( &
            "ESMF_TimeSet:  Must specify Sd if Sn is specified")
    ENDIF
    IF ( PRESENT( Sd ) .AND. PRESENT( MS ) ) THEN
       CALL wrf_error_fatal( &
            "ESMF_TimeSet:  Must not specify both Sd and MS")
    ENDIF
    time%basetime%Sn = 0
    time%basetime%Sd = 0
    IF ( PRESENT( MS ) ) THEN
       !  PRINT *,'DEBUG:  ESMF_TimeSet():  MS = ',MS
       time%basetime%Sn = MS
       time%basetime%Sd = 1000_ESMF_KIND_I8
    ELSE IF ( PRESENT( Sd ) ) THEN
       !  PRINT *,'DEBUG:  ESMF_TimeSet():  Sd = ',Sd
       time%basetime%Sd = Sd
       IF ( PRESENT( Sn ) ) THEN
          !  PRINT *,'DEBUG:  ESMF_TimeSet():  Sn = ',Sn
          time%basetime%Sn = Sn
       ENDIF
    ENDIF

    !  PRINT *,'DEBUG:  ESMF_TimeSet():  calling normalize_time()'
    !$$$DEBUG
    !IF ( time%basetime%Sd > 0 ) THEN
    !  PRINT *,'DEBUG ESMF_TimeSet() before normalize:  S,Sn,Sd = ', &
    !    time%basetime%S, time%basetime%Sn, time%basetime%Sd
    !ENDIF
    !$$$END DEBUG
    CALL normalize_time( time )
    !$$$DEBUG
    !IF ( time%basetime%Sd > 0 ) THEN
    !  PRINT *,'DEBUG ESMF_TimeSet() after normalize:  S,Sn,Sd = ', &
    !    time%basetime%S, time%basetime%Sn, time%basetime%Sd
    !ENDIF
    !$$$END DEBUG

    !  PRINT *,'DEBUG:  ESMF_TimeSet():  back from normalize_time()'
    IF ( PRESENT( rc ) ) THEN
       rc = ESMF_SUCCESS
    ENDIF

  end subroutine ESMF_TimeSet

  !------------------------------------------------------------------------------
  !BOP
  ! !IROUTINE:  ESMFold_TimeGetString - Get time instant value in string format

  ! !INTERFACE:
  subroutine ESMFold_TimeGetString( year, month, dayofmonth, &
       hour, minute, second, TimeString )

    ! !ARGUMENTS:
    integer, intent(in) :: year
    integer, intent(in) :: month
    integer, intent(in) :: dayofmonth
    integer, intent(in) :: hour
    integer, intent(in) :: minute
    integer, intent(in) :: second
    character*(*), intent(out) :: TimeString
    character*(256) :: TimeFormatString
    ! !DESCRIPTION:
    !     Convert {\tt ESMF\_Time}'s value into ISO 8601 format YYYY-MM-DDThh:mm:ss
    !
    !     The arguments are:
    !     \begin{description}
    !     \item[time]
    !          The object instance to convert
    !     \item[TimeString]
    !          The string to return
    !     \item[{[rc]}]
    !          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
    !     \end{description}
    !
    ! !REQUIREMENTS:
    !     TMG2.4.7
    !EOP

    !PRINT *,'DEBUG:  ESMF_TimePrint():  YR,S,Sn,Sd = ',time%YR,time%basetime%S,time%basetime%Sn,time%basetime%Sd
    !PRINT *,'DEBUG:  ESMF_TimePrint():  year = ',year
    !PRINT *,'DEBUG:  ESMF_TimePrint():  month, dayofmonth = ',month,dayofmonth
    !PRINT *,'DEBUG:  ESMF_TimePrint():  hour = ',hour
    !PRINT *,'DEBUG:  ESMF_TimePrint():  minute = ',minute
    !PRINT *,'DEBUG:  ESMF_TimePrint():  second = ',second

    !$$$here...  add negative sign for YR<0
    !$$$here...  add Sn, Sd ??
    write(TimeFormatString,FMT="(A,I4.4,A,I4.4,A)") &
         "(I", yearWidth, ".", yearWidth, ",'-',I2.2,'-',I2.2,'_',I2.2,':',I2.2,':',I2.2)"
    write(TimeString,FMT=TimeFormatString) year,month,dayofmonth,hour,minute,second

  end subroutine ESMFold_TimeGetString

  !------------------------------------------------------------------------------
  !BOP
  ! !IROUTINE: ESMF_TimeGetDayOfYearInteger - Get time instant's day of the year as an integer value
  !
  ! !INTERFACE:
  subroutine ESMF_TimeGetDayOfYearInteger(time, DayOfYear, rc)
    !
    ! !ARGUMENTS:
    type(ESMF_Time), intent(in) :: time
    integer, intent(out) :: DayOfYear
    integer, intent(out), optional :: rc
    !
    ! !DESCRIPTION:
    !     Get the day of the year the given {\tt ESMF\_Time} instant falls on
    !     (1-365).  Returned as an integer value
    !
    !     The arguments are:
    !     \begin{description}
    !     \item[time]
    !          The object instance to query
    !     \item[DayOfYear]
    !          The {\tt ESMF\_Time} instant's day of the year (1-365)
    !     \item[{[rc]}]
    !          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
    !     \end{description}
    !
    ! !REQUIREMENTS:
    !EOP
    ! requires that time be normalized
    !$$$ bug when Sn>0?  test
    !$$$ add tests
    DayOfYear = ( time%basetime%S / SECONDS_PER_DAY ) + 1
    IF ( PRESENT( rc ) ) rc = ESMF_SUCCESS
  end subroutine ESMF_TimeGetDayOfYearInteger

  !------------------------------------------------------------------------------
  !BOP
  ! !IROUTINE: ESMF_TimeInc - Increment time instant with a time interval
  !
  ! !INTERFACE:
  function ESMF_TimeInc(time, timeinterval)
    !
    ! !RETURN VALUE:
    type(ESMF_Time) :: ESMF_TimeInc
    !
    ! !ARGUMENTS:
    type(ESMF_Time), intent(in) :: time
    type(ESMF_TimeInterval), intent(in) :: timeinterval
    ! !LOCAL:
    INTEGER :: year,month,day,sec,nmon,nyr,mpyi4
    !
    ! !DESCRIPTION:
    !     Increment {\tt ESMF\_Time} instant with a {\tt ESMF\_TimeInterval},
    !     return resulting {\tt ESMF\_Time} instant
    !
    !     Maps overloaded (+) operator interface function to
    !     {\tt ESMF\_BaseTime} base class
    !
    !     The arguments are:
    !     \begin{description}
    !     \item[time]
    !          The given {\tt ESMF\_Time} to increment
    !     \item[timeinterval]
    !          The {\tt ESMF\_TimeInterval} to add to the given {\tt ESMF\_Time}
    !     \end{description}
    !
    ! !REQUIREMENTS:
    !     TMG1.5.4, TMG2.4.4, TMG2.4.5, TMG2.4.6, TMG5.1, TMG5.2, TMG7.2
    !EOP

    mpyi4 = MONTHS_PER_YEAR

    ! copy ESMF_Time specific properties (e.g. calendar, timezone)

    ESMF_TimeInc = time
    !      write(6,*) 'tcx timeinc1 ',ESMF_TimeInc%yr,ESMF_TimeInc%basetime%s
    CALL normalize_time( ESMF_TimeInc )

    !      write(6,*) 'tcx timeint ',timeinterval%yr,timeinterval%mm,timeinterval%basetime%s

    ! add years and months by manually forcing incremental years then adjusting the day of
    ! the month at the end if it's greater than the number of days in the month
    ! esmf seems to do exactly this based on testing

    nmon = timeinterval%mm
    nyr  = timeinterval%yr
    if (abs(nmon) > 0 .or. abs(nyr) > 0) then
       call ESMF_TimeGet(ESMF_TimeInc,yy=year,mm=month,dd=day,s=sec)
       !         write(6,*) 'tcx timeinc mon1 ',year,month,day,sec,nyr,nmon
       year  = year  + nyr
       month = month + nmon
       do while (month > MONTHS_PER_YEAR)
          month = month - mpyi4
          year = year + 1
       enddo
       do while (month < 1)
          month = month + mpyi4
          year = year - 1
       enddo
       !         write(6,*) 'tcx timeinc mon2 ',year,month,day,sec
       day = min(day,ndaysinmonth(year,month,ESMF_TimeInc%calendar%type))
       call ESMF_TimeSet(ESMF_TimeInc,yy=year,mm=month,dd=day,s=sec,calkindflag=time%calendar%type)
       call ESMF_TimeGet(ESMF_TimeInc,yy=year,mm=month,dd=day,s=sec)
       !         write(6,*) 'tcx timeinc mon3 ',nmon,year,month,day,sec
    endif

    ! finally add seconds

    !      write(6,*) 'tcx timeinc sec ',ESMF_TimeInc%basetime%s,timeinterval%basetime%s
    ESMF_TimeInc%basetime = ESMF_TimeInc%basetime + timeinterval%basetime

    ! and normalize

    !      write(6,*) 'tcx timeinc2p ',ESMF_TimeInc%yr,ESMF_TimeInc%basetime%s

    CALL normalize_time( ESMF_TimeInc )

    !      write(6,*) 'tcx timeinc2 ',ESMF_TimeInc%yr,ESMF_TimeInc%basetime%s

  end function ESMF_TimeInc

  ! this is added for certain compilers that don't deal with commutativity

  function ESMF_TimeInc2(timeinterval, time)
    type(ESMF_Time) :: ESMF_TimeInc2
    type(ESMF_Time), intent(in) :: time
    type(ESMF_TimeInterval), intent(in) :: timeinterval
    ESMF_TimeInc2 = ESMF_TimeInc( time, timeinterval )
  end function ESMF_TimeInc2

  !------------------------------------------------------------------------------
  !BOP
  ! !IROUTINE: ESMF_TimeDec - Decrement time instant with a time interval
  !
  ! !INTERFACE:
  function ESMF_TimeDec(time, timeinterval)
    !
    ! !RETURN VALUE:
    type(ESMF_Time) :: ESMF_TimeDec
    !
    ! !ARGUMENTS:
    type(ESMF_Time), intent(in) :: time
    type(ESMF_TimeInterval), intent(in) :: timeinterval
    ! !LOCAL:
    TYPE (ESMF_TimeInterval)  :: neginterval

    ! !DESCRIPTION:
    !     Decrement {\tt ESMF\_Time} instant with a {\tt ESMF\_TimeInterval},
    !     return resulting {\tt ESMF\_Time} instant
    !
    !     Maps overloaded (-) operator interface function to
    !     {\tt ESMF\_BaseTime} base class
    !
    !     The arguments are:
    !     \begin{description}
    !     \item[time]
    !          The given {\tt ESMF\_Time} to decrement
    !     \item[timeinterval]
    !          The {\tt ESMF\_TimeInterval} to subtract from the given
    !          {\tt ESMF\_Time}
    !     \end{description}
    !
    ! !REQUIREMENTS:
    !     TMG1.5.4, TMG2.4.4, TMG2.4.5, TMG2.4.6, TMG5.1, TMG5.2, TMG7.2
    !EOP

    ESMF_TimeDec = time

    neginterval = timeinterval
    !$$$push this down into a unary negation operator on TimeInterval
    neginterval%basetime%S = -neginterval%basetime%S
    neginterval%basetime%Sn = -neginterval%basetime%Sn
    neginterval%YR = -neginterval%YR
    neginterval%MM = -neginterval%MM
    ESMF_TimeDec = time + neginterval

  end function ESMF_TimeDec

  !
  ! this is added for certain compilers that don't deal with commutativity
  !
  function ESMF_TimeDec2(timeinterval, time)
    type(ESMF_Time) :: ESMF_TimeDec2
    type(ESMF_Time), intent(in) :: time
    type(ESMF_TimeInterval), intent(in) :: timeinterval
    ESMF_TimeDec2 = ESMF_TimeDec( time, timeinterval )
  end function ESMF_TimeDec2
  !
  !------------------------------------------------------------------------------
  !BOP
  ! !IROUTINE:  ESMF_TimeDiff - Return the difference between two time instants
  !
  ! !INTERFACE:
  function ESMF_TimeDiff(time1, time2)
    !
    ! !RETURN VALUE:
    type(ESMF_TimeInterval) :: ESMF_TimeDiff
    !
    ! !ARGUMENTS:
    type(ESMF_Time), intent(in) :: time1
    type(ESMF_Time), intent(in) :: time2
    ! !LOCAL:
    TYPE(ESMF_BaseTime) :: cmptime, zerotime
    integer :: yr
    integer :: y1,m1,d1,s1,y2,m2,d2,s2
    integer :: rc

    ! !DESCRIPTION:
    !     Return the {\tt ESMF\_TimeInterval} difference between two
    !     {\tt ESMF\_Time} instants, time1 - time2
    !
    !     Maps overloaded (-) operator interface function to
    !     {\tt ESMF\_BaseTime} base class
    !
    !     The arguments are:
    !     \begin{description}
    !     \item[time1]
    !          The first {\tt ESMF\_Time} instant
    !     \item[time2]
    !          The second {\tt ESMF\_Time} instant
    !     \end{description}
    !
    ! !REQUIREMENTS:
    !     TMG1.5.4, TMG2.4.4, TMG2.4.5, TMG2.4.6, TMG5.1, TMG5.2, TMG7.2
    !EOP

    CALL ESMF_TimeIntervalSet( ESMF_TimeDiff, rc=rc )

    ESMF_TimeDiff%StartTime = time2
    ESMF_TimeDiff%StartTime_set = .true.

    !      write(6,*) 'tcx timediff1 ',time2%yr,time2%basetime%s,time2%calendar%type%caltype
    !      write(6,*) 'tcx timediff2 ',time1%yr,time1%basetime%s,time1%calendar%type%caltype

    call ESMF_TimeGet(time2,yy=y2,mm=m2,dd=d2,s=s2)
    call ESMF_TimeGet(time1,yy=y1,mm=m1,dd=d1,s=s1)

    ! Can either be yr/month based diff if diff is only in year and month
    ! or absolute seconds if diff in day/seconds as well
    !
    ! Update: Actually, the timeintcmp() routine in ESMF_TimeIntervalMod.F90 is not capable
    !    of comparing time intervals when one interval has a different year and month than
    !    the other. So, it is best here to always compute the interval as day/seconds.

    !      if (d1 == d2 .and. s1 == s2) then
    !!         write(6,*) 'tcx timedifft ym'
    !         ESMF_TimeDiff%YR = y1 - y2
    !         ESMF_TimeDiff%MM = m1 - m2
    !         cmptime%S  = 0
    !         cmptime%Sn = 0
    !         cmptime%Sd = 0
    !         ESMF_TimeDiff%basetime = cmptime
    !      else
    !         write(6,*) 'tcx timedifft sec'
    ESMF_TimeDiff%YR = 0
    ESMF_TimeDiff%MM = 0
    ESMF_TimeDiff%basetime = time1%basetime - time2%basetime
    IF ( time1%YR > time2%YR ) THEN
       DO yr = time2%YR, ( time1%YR - 1 )
          !              write(6,*) 'tcx timediff3 ',yr,nsecondsinyear(yr,time2%calendar%type)
          ESMF_TimeDiff%basetime%S = ESMF_TimeDiff%basetime%S + nsecondsinyear(yr,time2%calendar%type)
       ENDDO
    ELSE IF ( time2%YR > time1%YR ) THEN
       DO yr = time1%YR, ( time2%YR - 1 )
          !              write(6,*) 'tcx timediff4 ',yr,nsecondsinyear(yr,time2%calendar%type)
          ESMF_TimeDiff%basetime%S = ESMF_TimeDiff%basetime%S - nsecondsinyear(yr,time2%calendar%type)
       ENDDO
    ENDIF
    !      endif

    !      write(6,*) 'tcx timediff5 ',ESMF_TimeDiff%YR, ESMF_TimeDiff%MM, ESMF_TimeDiff%basetime%s

    CALL normalize_timeint( ESMF_TimeDiff )

    !      write(6,*) 'tcx timediff6 ',ESMF_TimeDiff%YR, ESMF_TimeDiff%MM, ESMF_TimeDiff%basetime%s

  end function ESMF_TimeDiff

  !------------------------------------------------------------------------------
  !BOP
  ! !IROUTINE: ESMF_TimeEQ - Compare two times for equality
  !
  ! !INTERFACE:
  function ESMF_TimeEQ(time1, time2)
    !
    ! !RETURN VALUE:
    logical :: ESMF_TimeEQ
    !
    ! !ARGUMENTS:
    type(ESMF_Time), intent(in) :: time1
    type(ESMF_Time), intent(in) :: time2
    !
    ! !DESCRIPTION:
    !     Return true if both given {\tt ESMF\_Time} instants are equal, false
    !     otherwise.  Maps overloaded (==) operator interface function to
    !     {\tt ESMF\_BaseTime} base class.
    !
    !     The arguments are:
    !     \begin{description}
    !     \item[time1]
    !          First time instant to compare
    !     \item[time2]
    !          Second time instant to compare
    !     \end{description}
    !
    ! !REQUIREMENTS:
    !     TMG1.5.3, TMG2.4.3, TMG7.2
    !EOP

    integer :: res

    call timecmp(time1,time2,res)
    ESMF_TimeEQ = (res .EQ. 0)

  end function ESMF_TimeEQ

  !------------------------------------------------------------------------------
  !BOP
  ! !IROUTINE: ESMF_TimeNE - Compare two times for non-equality
  !
  ! !INTERFACE:
  function ESMF_TimeNE(time1, time2)
    !
    ! !RETURN VALUE:
    logical :: ESMF_TimeNE
    !
    ! !ARGUMENTS:
    type(ESMF_Time), intent(in) :: time1
    type(ESMF_Time), intent(in) :: time2

    ! !DESCRIPTION:
    !     Return true if both given {\tt ESMF\_Time} instants are not equal, false
    !     otherwise.  Maps overloaded (/=) operator interface function to
    !     {\tt ESMF\_BaseTime} base class.
    !
    !     The arguments are:
    !     \begin{description}
    !     \item[time1]
    !          First time instant to compare
    !     \item[time2]
    !          Second time instant to compare
    !     \end{description}
    !
    ! !REQUIREMENTS:
    !     TMG1.5.3, TMG2.4.3, TMG7.2
    !EOP

    integer :: res

    call timecmp(time1,time2,res)
    ESMF_TimeNE = (res .NE. 0)

  end function ESMF_TimeNE

  !------------------------------------------------------------------------------
  !BOP
  ! !IROUTINE: ESMF_TimeLT - Time instant 1 less than time instant 2 ?
  !
  ! !INTERFACE:
  function ESMF_TimeLT(time1, time2)
    !
    ! !RETURN VALUE:
    logical :: ESMF_TimeLT
    !
    ! !ARGUMENTS:
    type(ESMF_Time), intent(in) :: time1
    type(ESMF_Time), intent(in) :: time2
    !
    ! !DESCRIPTION:
    !     Return true if first {\tt ESMF\_Time} instant is less than second
    !     {\tt ESMF\_Time} instant, false otherwise.  Maps overloaded (<)
    !     operator interface function to {\tt ESMF\_BaseTime} base class.
    !
    !     The arguments are:
    !     \begin{description}
    !     \item[time1]
    !          First time instant to compare
    !     \item[time2]
    !          Second time instant to compare
    !     \end{description}
    !
    ! !REQUIREMENTS:
    !     TMG1.5.3, TMG2.4.3, TMG7.2
    !EOP

    integer :: res

    call timecmp(time1,time2,res)
    ESMF_TimeLT = (res .LT. 0)

  end function ESMF_TimeLT

  !------------------------------------------------------------------------------
  !BOP
  ! !IROUTINE: ESMF_TimeGT - Time instant 1 greater than time instant 2 ?
  !
  ! !INTERFACE:
  function ESMF_TimeGT(time1, time2)
    !
    ! !RETURN VALUE:
    logical :: ESMF_TimeGT
    !
    ! !ARGUMENTS:
    type(ESMF_Time), intent(in) :: time1
    type(ESMF_Time), intent(in) :: time2
    !
    ! !DESCRIPTION:
    !     Return true if first {\tt ESMF\_Time} instant is greater than second
    !     {\tt ESMF\_Time} instant, false otherwise.  Maps overloaded (>) operator
    !     interface function to {\tt ESMF\_BaseTime} base class.
    !
    !     The arguments are:
    !     \begin{description}
    !     \item[time1]
    !          First time instant to compare
    !     \item[time2]
    !          Second time instant to compare
    !     \end{description}
    !
    ! !REQUIREMENTS:
    !     TMG1.5.3, TMG2.4.3, TMG7.2
    !EOP

    integer :: res

    call timecmp(time1,time2,res)
    ESMF_TimeGT = (res .GT. 0)

  end function ESMF_TimeGT

  !------------------------------------------------------------------------------
  !BOP
  ! !IROUTINE: ESMF_TimeLE - Time instant 1 less than or equal to time instant 2 ?
  !
  ! !INTERFACE:
  function ESMF_TimeLE(time1, time2)
    !
    ! !RETURN VALUE:
    logical :: ESMF_TimeLE
    !
    ! !ARGUMENTS:
    type(ESMF_Time), intent(in) :: time1
    type(ESMF_Time), intent(in) :: time2
    !
    ! !DESCRIPTION:
    !     Return true if first {\tt ESMF\_Time} instant is less than or equal to
    !     second {\tt ESMF\_Time} instant, false otherwise.  Maps overloaded (<=)
    !     operator interface function to {\tt ESMF\_BaseTime} base class.
    !
    !     The arguments are:
    !     \begin{description}
    !     \item[time1]
    !          First time instant to compare
    !     \item[time2]
    !          Second time instant to compare
    !     \end{description}
    !
    ! !REQUIREMENTS:
    !     TMG1.5.3, TMG2.4.3, TMG7.2
    !EOP

    integer :: res

    call timecmp(time1,time2,res)
    ESMF_TimeLE = (res .LE. 0)

  end function ESMF_TimeLE

  !------------------------------------------------------------------------------
  !BOP
  ! !IROUTINE: ESMF_TimeGE - Time instant 1 greater than or equal to time instant 2 ?
  !
  ! !INTERFACE:
  function ESMF_TimeGE(time1, time2)
    !
    ! !RETURN VALUE:
    logical :: ESMF_TimeGE
    !
    ! !ARGUMENTS:
    type(ESMF_Time), intent(in) :: time1
    type(ESMF_Time), intent(in) :: time2
    !
    ! !DESCRIPTION:
    !     Return true if first {\tt ESMF\_Time} instant is greater than or equal to
    !     second {\tt ESMF\_Time} instant, false otherwise.  Maps overloaded (>=)
    !     operator interface function to {\tt ESMF\_BaseTime} base class.
    !
    !     The arguments are:
    !     \begin{description}
    !     \item[time1]
    !          First time instant to compare
    !     \item[time2]
    !          Second time instant to compare
    !     \end{description}
    !
    ! !REQUIREMENTS:
    !     TMG1.5.3, TMG2.4.3, TMG7.2
    !EOP

    integer :: res

    call timecmp(time1,time2,res)
    ESMF_TimeGE = (res .GE. 0)

  end function ESMF_TimeGE

  !------------------------------------------------------------------------------
  !BOP
  ! !IROUTINE:  ESMF_TimeCopy - Copy a time-instance

  ! !INTERFACE:
  subroutine ESMF_TimeCopy(timeout, timein)

    ! !ARGUMENTS:
    type(ESMF_Time), intent(out) :: timeout
    type(ESMF_Time), intent(in) :: timein

    ! !DESCRIPTION:
    !     Copy a time-instance to a new instance.
    !
    !     \item[{[rc]}]
    !          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
    !     \end{description}
    !
    ! !REQUIREMENTS:
    !     TMGn.n.n
    !EOP

    timeout%basetime = timein%basetime
    timeout%YR       = timein%YR
    timeout%Calendar => timein%Calendar
    !tcx      timeout%Calendar = timein%Calendar
    !      write(6,*) 'tcxa ESMF_TimeCopy'
    !      call flush(6)
    !      write(6,*) 'tcxb ESMF_TimeCopy',timein%calendar%type%caltype
    !      call flush(6)
    timeout%Calendar = ESMF_CalendarCreate(calkindflag=timein%calendar%type)

  end subroutine ESMF_TimeCopy


  !------------------------------------------------------------------------------
  !BOP
  ! !IROUTINE:  ESMF_TimePrint - Print out a time instant's properties


  ! !INTERFACE:
  subroutine ESMF_TimePrint(time, options, rc)

    ! !ARGUMENTS:
    type(ESMF_Time), intent(in) :: time
    character (len=*), intent(in), optional :: options
    integer, intent(out), optional :: rc
    character (len=256) :: timestr

    ! !DESCRIPTION:
    !     To support testing/debugging, print out a {\tt ESMF\_Time}'s
    !     properties.
    !
    !     The arguments are:
    !     \begin{description}
    !     \item[time]
    !          {\tt ESMF\_Time} instant to print out
    !     \item[{[options]}]
    !          Print options
    !     \item[{[rc]}]
    !          Return code; equals {\tt ESMF\_SUCCESS} if there are no errors.
    !     \end{description}
    !
    ! !REQUIREMENTS:
    !     TMGn.n.n
    !EOP

    ! Quick hack to mimic ESMF 2.0.1
    ! Really should check value of options...
    IF ( PRESENT( options ) ) THEN
       CALL ESMF_TimeGet( time, timeString=timestr, rc=rc )
       timestr(11:11) = 'T'     ! ISO 8601 compatibility hack for debugging
       print *,' Time -----------------------------------'
       print *,' ',TRIM(timestr)
       print *,' end Time -------------------------------'
       print *
    ELSE
       call print_a_time (time)
    ENDIF

  end subroutine ESMF_TimePrint

  !==============================================================================

  SUBROUTINE print_a_time( time )
    IMPLICIT NONE
    type(ESMF_Time) time
    character*128 :: s
    integer rc
    CALL ESMF_TimeGet( time, timeString=s, rc=rc )
    print *,'Print a time|',TRIM(s),'|'
    write(0,*)'Print a time|',TRIM(s),'|'
    return
  END SUBROUTINE print_a_time

  !==============================================================================

  SUBROUTINE timecmp(time1, time2, retval )
    IMPLICIT NONE
    INTEGER, INTENT(OUT) :: retval
    !
    ! !ARGUMENTS:
    TYPE(ESMF_Time), INTENT(IN) :: time1
    TYPE(ESMF_Time), INTENT(IN) :: time2
    IF ( time1%YR .GT. time2%YR ) THEN ; retval = 1  ; RETURN ; ENDIF
       IF ( time1%YR .LT. time2%YR ) THEN ; retval = -1 ; RETURN ; ENDIF
          CALL seccmp( time1%basetime%S, time1%basetime%Sn, time1%basetime%Sd, &
               time2%basetime%S, time2%basetime%Sn, time2%basetime%Sd, &
	       retval )
        END SUBROUTINE timecmp

        !==============================================================================

        SUBROUTINE normalize_time( time )
          ! A normalized time has time%basetime >= 0, time%basetime less than the current
          ! year expressed as a timeInterval, and time%YR can take any value
          IMPLICIT NONE
          TYPE(ESMF_Time), INTENT(INOUT) :: time
          !  INTEGER(ESMF_KIND_I8) :: nsecondsinyear
          ! locals
          TYPE(ESMF_BaseTime) :: cmptime, zerotime
          INTEGER :: rc
          LOGICAL :: done

          ! first, normalize basetime
          ! this will force abs(Sn) < Sd and ensure that signs of S and Sn match

          CALL normalize_basetime( time%basetime )

          ! next, underflow negative seconds into YEARS
          ! time%basetime must end up non-negative

          zerotime%S  = 0
          zerotime%Sn = 0
          zerotime%Sd = 0
          DO WHILE ( time%basetime < zerotime )
             time%YR = time%YR - 1
             cmptime%S  = nsecondsinyear( time%YR, time%calendar%type )
             cmptime%Sn = 0
             cmptime%Sd = 0
             time%basetime = time%basetime + cmptime
          ENDDO

          ! next, overflow seconds into YEARS
          done = .FALSE.
          DO WHILE ( .NOT. done )
             cmptime%S  = nsecondsinyear( time%YR, time%calendar%type )
             cmptime%Sn = 0
             cmptime%Sd = 0
             IF ( time%basetime >= cmptime ) THEN
                time%basetime = time%basetime - cmptime
                time%YR = time%YR + 1
             ELSE
                done = .TRUE.
             ENDIF
          ENDDO

        END SUBROUTINE normalize_time

        !==============================================================================

        SUBROUTINE timegetmonth( time, MM )
          IMPLICIT NONE
          TYPE(ESMF_Time), INTENT(IN) :: time
          INTEGER, INTENT(OUT) :: MM
          ! locals

          mm = nmonthinyearsec(time%yr,time%basetime,time%calendar%type)

        END SUBROUTINE timegetmonth

        !==============================================================================
        SUBROUTINE timegetdayofmonth( time, DD )
          IMPLICIT NONE
          TYPE(ESMF_Time), INTENT(IN) :: time
          INTEGER, INTENT(OUT) :: DD
          ! locals

          dd = ndayinyearsec(time%yr, time%basetime, time%calendar%type)

        END SUBROUTINE timegetdayofmonth

        !==============================================================================

        ! Increment Time by number of seconds between start of year and start
        ! of month MM.
        ! 1 <= MM <= 12
        ! Time is NOT normalized.
        SUBROUTINE timeaddmonths( time, MM, ierr )
          IMPLICIT NONE
          TYPE(ESMF_Time), INTENT(INOUT) :: time
          INTEGER, INTENT(IN) :: MM
          INTEGER, INTENT(OUT) :: ierr
          ! locals
          INTEGER(ESMF_KIND_I8) :: isec

          ierr = ESMF_SUCCESS
          IF ( ( MM < 1 ) .OR. ( MM > MONTHS_PER_YEAR ) ) THEN
             CALL wrf_message( 'ERROR timeaddmonths():  MM out of range' )
             ierr = ESMF_FAILURE
             return
          ENDIF

          isec = nsecondsinyearmonth(time%yr,MM,time%calendar%type)
          time%basetime%s = time%basetime%s + isec

        END SUBROUTINE timeaddmonths

        !==============================================================================

        ! Increment Time by number of seconds between start of year and start
        ! of month MM.
        ! 1 <= MM <= 12
        ! Time is NOT normalized.
        SUBROUTINE ESMF_setYearWidth( yearWidthIn )

          integer, intent(in) :: yearWidthIn

          yearWidth = yearWidthIn

        END SUBROUTINE ESMF_setYearWidth

        !==============================================================================
        !==============================================================================
      end module ESMF_TimeMod
